﻿using AntdUI;
using AntdUI.Svg;
using BST250301;
using BST250301.Views;
using BST250301TestStand.Models.Helpers;
using BST250301TestStand.Models.Utils;
using Google.Protobuf.WellKnownTypes;
using MathNet.Numerics.Distributions;
using MathNet.Numerics.Interpolation;
using NPOI.SS.Formula.Functions;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using static OpenTK.Graphics.OpenGL.GL;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel;

namespace BST250301TestStand.Models
{
    internal class Operation
    {
        public static bool IsTCUOnline = true;
        public static bool IsNVHOnline = true;
        public static bool IsPLCOnline = true;

        /// <summary>
        /// 初始化离合器，全部断开
        /// </summary>
        /// <returns></returns>
        public static async Task<bool> StartClutchInit()
        {
            try
            {

                Operation.SetCFCREn(true);//使能开
                Operation.SetCFCRShp(ClutcCFCR.N);//先空挡

                //CF电磁阀初始值
                Operation.SetCurrentChan(CurrentChannel.CF);
                Operation.SetCurrenCF(0);

                //CR电磁阀初始值
                Operation.SetCurrentChan(CurrentChannel.CR);
                Operation.SetCurrenCR(0);


                //CPTO离合器
                Operation.SetCPTOEn(true);//使能开
                Operation.SetCPTOOnOff(false);
                Operation.SetCurrentChan(CurrentChannel.CPTO);
                Operation.SetCurrenCPTO(0);
                Operation.SetCurrentChan(CurrentChannel.CR);

                await Task.Delay(3000);
                Operation.SetCPTOEn(false);//关闭使能
                Operation.SetCFCREn(false);//关闭CF CR使能
                Operation.SetCurrentChan(CurrentChannel.None);//关闭通道

                return true;

            }
            catch (Exception ex)
            {
                return false;
            }
        }
        /// <summary>
        /// 清理CAN缓存
        /// </summary>
        /// <returns></returns>
        public static bool ZCAN_ClearBuffer()
        {
            return TCUConfig.ClearBuffer();
        }
        /// <summary>
        /// 关闭CAN通道
        /// 
        /// </summary>
        /// <returns></returns>
        public static bool ZCAN_CloseCan()
        {
            return TCUConfig.CloseCan();
        }
        /// <summary>
        /// PLC加载端启动
        /// </summary>
        /// <param name="isStartStop"></param>
        /// <returns></returns>
        public static bool PLCDriverStart(bool isStartStop)
        {
            return PLCConfig.SetPLCDriverStart(isStartStop);

        }
        /// <summary>
        /// 加载端启动
        /// </summary>
        /// <param name="isStartStop"></param>
        /// <returns></returns>
        public static bool PLCLoadStart(bool isStartStop)
        {
            return PLCConfig.SetPLCLoadStart(isStartStop);

        }
        /// <summary>
        /// D档-前进
        /// </summary>
        /// <param name="isStartStop"></param>
        /// <returns></returns>
        public static bool PLCD(bool isStartStop)
        {
            return PLCConfig.SetPLCD(isStartStop);

        }
        /// <summary>
        /// R档-后退
        /// </summary>
        /// <param name="isStartStop"></param>
        /// <returns></returns>
        public static bool PLCR(bool isStartStop)
        {
            return PLCConfig.SetPLCR(isStartStop);

        }
        /// <summary>
        /// 驱动端对接
        /// </summary>
        /// <param name="isStartStop"></param>
        /// <returns></returns>
        public static bool PLCDriverConnect(bool isStartStop)
        {
            return PLCConfig.SetPLCDriverConnect(isStartStop);

        }
        /// <summary>
        /// 驱动端松开
        /// </summary>
        /// <param name="isStartStop"></param>
        /// <returns></returns>
        public static bool PLCDriverDisconnect(bool isStartStop)
        {
            return PLCConfig.SetPLCDriverDisconnect(isStartStop);

        }
        /// <summary>
        /// 加载端对接
        /// </summary>
        /// <param name="isStartStop"></param>
        /// <returns></returns>
        public static bool PLCLoadConnect(bool isStartStop)
        {
            return PLCConfig.SetPLCLoadConnect(isStartStop);

        }
        /// <summary>
        /// 加载端松开
        /// </summary>
        /// <param name="isStartStop"></param>
        /// <returns></returns>
        public static bool PLCLoadDisconnect(bool isStartStop)
        {
            return PLCConfig.SetPLCLoadDisconnect(isStartStop);

        }
        /// <summary>
        /// 加温启动
        /// </summary>
        /// <param name="isStartStop"></param>
        /// <returns></returns>
        public static bool PLCTempaAdd(bool isStartStop)
        {
            return PLCConfig.SetPLCTempaAdd(isStartStop);

        }
        /// <summary>
        /// 降温启动
        /// </summary>
        /// <param name="isStartStop"></param>
        /// <returns></returns>
        public static bool PLCTempaSub(bool isStartStop)
        {
            return PLCConfig.SetPLCTempaSub(isStartStop);

        }
        /// <summary>
        /// 设置油温
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool SetOilTempa(TOil value)
        {
            try
            {
                switch (value)
                {
                    case TOil.t40_3:
                    case TOil.t40_5:
                        PLCConfig.SetPLCOilTempa(40);
                        break;
                    case TOil.t80_3:
                    case TOil.t80_5:
                        PLCConfig.SetPLCOilTempa(80);
                        break;
                    case TOil.常温:
                    default:
                        PLCConfig.SetPLCOilTempa(0);
                        break;
                }
                return true;


            }
            catch (Exception)
            {
                return false;
            }
        }
        public static bool SetOilTempa(float value)
        {
            return PLCConfig.SetPLCOilTempa(value);

        }
        /// <summary>
        /// 设置转矩
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool SetTorque(float value)
        {
            return PLCConfig.SetPLCTorque(value);
        }
        /// <summary>
        /// 设置启动速度
        /// </summary>
        /// <param name="test"></param>
        /// <returns></returns>
        public static async Task<bool> SetGetStartSpeed(StepTest test)
        {
            return await PLCConfig.SetPLCSpeed(test.ValueStart, true);
        }

        /// <summary>
        /// 设置转速
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static async Task<bool> SetSpeed(StepTest test)
        {
            try
            {
                //确保驱动端在使能状态

                if (test.StepValue == 0 && test.StepKeep == 0)//如果不是阶跃
                    return await PLCConfig.SetGetPLCSpeedAndTestSpeed(test.ValueStart);

                await Task.Run(async () =>
                {
                    int lastvaule = test.ValueStart;
                    //int step = ((1610 - 0)+40-1) / 40;//为了得到不舍只入。
                    int step = ((test.ValueEnd - test.ValueStart) + test.StepValue - 1) / test.StepValue;//为了得到不舍只入的步数。
                    for (int i = 0; i < step; i++)
                    {
                        lastvaule = test.ValueStart + i * test.StepValue;

                        await PLCConfig.SetPLCSpeed(lastvaule, false);

                        Stopwatch stopwatch = new Stopwatch();
                        stopwatch.Start();
                        while (true)
                        {
                            if (!ShowStatus.IsRunning)
                                return;
                            if (stopwatch.ElapsedMilliseconds >= test.StepKeep * 1000)//达到阶跃秒数
                            {
                                break;
                            }
                        }
                        stopwatch.Stop();
                    }
                    //峰值回落
                    for (int i = 1; i < step; i++)
                    {
                        var val = lastvaule - i * test.StepValue;
                        if (val < 0)
                        {
                            await PLCConfig.SetPLCSpeed(0, false);
                        }
                        else
                            await PLCConfig.SetPLCSpeed(val, false);

                        Stopwatch stopwatch = new Stopwatch();
                        stopwatch.Start();
                        while (true)
                        {
                            if (!ShowStatus.IsRunning)
                                return;
                            if (stopwatch.ElapsedMilliseconds >= test.StepKeep * 1000)//达到阶跃秒数
                            {
                                break;
                            }
                        }
                        stopwatch.Stop();
                    }
                });
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
        /// <summary>
        /// 设置电磁阀阶跃（如有）
        /// </summary>
        /// <param name="test"></param>
        /// <returns></returns>
        public static async Task<bool> SetCFCRCPTOStep(StepTest test, string cfcrcpto, ProjectItem projectItem)
        {
            if (test.StepValue == 0 && test.StepKeep == 0)//如果不是阶跃
            {
                if (cfcrcpto == "CF")
                    SetCurrenCF(test.ValueStart);
                else if (cfcrcpto == "CR")
                    SetCurrenCR(test.ValueStart);
                else if (cfcrcpto == "CPTO")
                    SetCurrenCPTO(test.ValueStart);

                return false;
            }

            if (test.SPCMode == 2)
            {
                return await SetCFCRCPTOStepPulse(test, cfcrcpto, projectItem);
            }
            else if (test.SPCMode == 3)
            {
                return await SetCFCRCPTOStepKP(test, cfcrcpto, projectItem);
            }

            try
            {
                var recrddata = new ShowDataRecord
                {
                    Title = cfcrcpto,
                    Unit = "mA",
                    ListC = new List<double>(),
                    ListS = new List<double>(),
                    ListX = new List<double>(),
                    ListY = new List<double>(),
                };
                var recrddataMirrorAVG = new ShowDataRecord
                {
                    Title = cfcrcpto,
                    Unit = "mA",
                    ListC = new List<double>(),
                    ListS = new List<double>(),
                    ListX = new List<double>(),
                    ListY = new List<double>(),
                };
                var recrddataAVGStep = new ShowDataRecord
                {
                    Title = cfcrcpto,
                    Unit = "mA",
                    ListC = new List<double>(),
                    ListS = new List<double>(),
                    ListX = new List<double>(),
                    ListY = new List<double>(),
                };
                int stable90 = 0;
                bool is90 = false;
                int stable10 = 0;
                bool is10 = false;
                int stepPiek = 0;
                await Task.Run(async () =>
                {
                    int lastvaule = test.ValueStart;
                    //int step = ((1610 - 0)+40-1) / 40;//为了得到不舍只入。
                    int step = ((test.ValueEnd - test.ValueStart) + test.StepValue - 1) / test.StepValue;//为了得到不舍只入的步数。
                    int startRecodS = 2;//记录开始时间
                    stepPiek = step;//记录峰值阶跃数字

                    for (int i = 0; i < step + 1; i++)
                    {
                        lastvaule = test.ValueStart + i * test.StepValue;
                        if (cfcrcpto == "CF")
                            SetCurrenCF(lastvaule);
                        else if (cfcrcpto == "CR")
                            SetCurrenCR(lastvaule);
                        else if (cfcrcpto == "CPTO")
                            SetCurrenCPTO(lastvaule);

                        int countstep = 0;
                        double addstep = 0;
                        double addstepCtl = 0;

                        Stopwatch stopwatch = new Stopwatch();
                        stopwatch.Start();
                        while (true)
                        {
                            if (!ShowStatus.IsRunning)
                                return;
                            await Task.Delay(MainWindow.configapp.TCUInterval);
                            double pressure = 0;
                            double ctr_current = 0;
                            if (cfcrcpto == "CF")
                            {
                                pressure = ShowStatus.CF_Pressure;
                                ctr_current = ShowStatus.CF_ControlCurrent;
                            }
                            else if (cfcrcpto == "CR")
                            {
                                pressure = ShowStatus.CR_Pressure;
                                ctr_current = ShowStatus.CR_ControlCurrent;
                            }
                            else if (cfcrcpto == "CPTO")
                            {
                                pressure = ShowStatus.CPTO_Pressure;
                                ctr_current = ShowStatus.PTO_ControlCurrent;
                            }
                            if (stopwatch.ElapsedMilliseconds >= startRecodS * 1000)//达到记录开始时间
                            {
                                countstep++;
                                //double pressure = 0;
                                //double ctr_current = 0;
                                
                                double ms = stopwatch.Elapsed.TotalSeconds;
                                recrddata.ListC.Add(ctr_current);
                                recrddata.ListS.Add(lastvaule);
                                var mss = i * test.StepKeep + ms;
                                recrddata.ListX.Add(mss);
                                recrddata.ListY.Add(pressure);

                                addstep += pressure;
                                addstepCtl += ctr_current;
                            }
                            if (pressure >= MainWindow.configapp.StableBar_90 && !is90)//达到设定（config.json）稳定压力
                            {
                                is90 = true;
                                stable90 = (int)stopwatch.ElapsedMilliseconds;
                            }
                            if (stopwatch.ElapsedMilliseconds >= test.StepKeep * 1000)//达到阶跃秒数
                            {
                                break;
                            }
                        }
                        recrddataAVGStep.ListC.Add(addstepCtl / countstep);
                        recrddataAVGStep.ListY.Add(addstep / countstep);

                        stopwatch.Stop();
                    }
                    //峰值回落
                    for (int i = 1; i < step + 1; i++)
                    {
                        var val = lastvaule - i * test.StepValue;
                        if (val < 0)
                        {
                            val = 0;
                        }
                        if (cfcrcpto == "CF")
                            SetCurrenCF(val);
                        else if (cfcrcpto == "CR")
                            SetCurrenCR(val);
                        else if (cfcrcpto == "CPTO")
                            SetCurrenCPTO(val);

                        int countstep = 0;
                        double addstep = 0;
                        double addstepCtl = 0;
                        Stopwatch stopwatch = new Stopwatch();
                        stopwatch.Start();
                        while (true)
                        {
                            if (!ShowStatus.IsRunning)
                                return;
                            await Task.Delay(MainWindow.configapp.TCUInterval);
                            double pressure = 0;
                            double ctr_current = 0;
                            if (cfcrcpto == "CF")
                            {
                                pressure = ShowStatus.CF_Pressure;
                                ctr_current = ShowStatus.CF_ControlCurrent;
                            }
                            else if (cfcrcpto == "CR")
                            {
                                pressure = ShowStatus.CR_Pressure;
                                ctr_current = ShowStatus.CR_ControlCurrent;
                            }
                            else if (cfcrcpto == "CPTO")
                            {
                                pressure = ShowStatus.CPTO_Pressure;
                                ctr_current = ShowStatus.PTO_ControlCurrent;
                            }
                            if (stopwatch.ElapsedMilliseconds >= startRecodS * 1000)//达到记录开始时间
                            {
                                countstep++;
                                //double pressure = 0;
                                //double ctr_current = 0;                                
                                double ms = stopwatch.Elapsed.TotalSeconds;
                                recrddata.ListC.Add(ctr_current);
                                recrddata.ListS.Add(val);
                                var mss = step * test.StepKeep + i * test.StepKeep + ms;
                                recrddata.ListX.Add(mss);
                                recrddata.ListY.Add(pressure);

                                addstep += pressure;
                                addstepCtl += ctr_current;
                            }
                            if (pressure <= MainWindow.configapp.StableBar_10 && !is10)//达到设定（config.json）稳定压力
                            {
                                is10 = true;
                                stable10 = (int)stopwatch.ElapsedMilliseconds;
                            }
                            if (stopwatch.ElapsedMilliseconds >= test.StepKeep * 1000)//达到阶跃秒数
                            {
                                break;
                            }
                        }
                        recrddataAVGStep.ListC.Add(addstepCtl / countstep);
                        recrddataAVGStep.ListY.Add(addstep / countstep);

                        stopwatch.Stop();
                    }
                });
                ShowStatus.STABLE90 = stable90;
                ShowStatus.STABLE10 = stable10;
                var dtdatetime = DateTime.Now;

                //报存原始数据
                SaveData(projectItem, cfcrcpto, recrddata, dtdatetime);
                var recrddataAlpha = new ShowDataRecord
                {
                    Title = cfcrcpto,
                    Unit = "mA",
                    ListC = new List<double>(),
                    ListS = new List<double>(),
                    ListX = new List<double>(),
                    ListY = new List<double>(),
                };
                recrddataAlpha = GetLowPassFilter(MainWindow.configapp.FilterAlpha, recrddata);
                SaveDataFilter(projectItem, cfcrcpto, recrddataAlpha, dtdatetime);
                //保存平均值
                string filepathfile = await SaveData(projectItem, cfcrcpto + "_AVG", recrddataAVGStep, dtdatetime);

                //计算对称位置的平均值
                recrddataMirrorAVG.ListC = DataTranslate.CalculateSymmetricAverages(recrddataAVGStep.ListC);//C是平均电流
                                                                                                            //recrddataMirrorAVG.ListC = DataTranslate.CalculateSymmetricAverages(new List<double>() { 50, 60, 70, 80, 90, 100, 110, 600, 900, 600, 1100, 1400, 1000, 1200, 900, 800, 700, 800, 600, 500, 400 });//C是平均电流
                recrddataMirrorAVG.ListY = DataTranslate.CalculateSymmetricAverages(recrddataAVGStep.ListY);//Y是平均压力
                                                                                                            //recrddataMirrorAVG.ListY = DataTranslate.CalculateSymmetricAverages(new List<double>() { 1,1.1,1.3,1.5,1.8,1.9,2.0,3.1,4.1,5.5,15,20,19.5,18.5,15.5,10.5,8.5,6.5,3.5,1.6,0});//Y是平均压力
                recrddataMirrorAVG.ListX.Clear();
                for (int i = 0; i < recrddataMirrorAVG.ListY.Count; i++)
                {
                    recrddataMirrorAVG.ListX.Add(recrddataMirrorAVG.ListY[i]);//X是对称平均压力
                }
                //保存对称位置平均值
                //SaveData(projectItem, cfcrcpto + "_Mirror_AVG", recrddataMirrorAVG);
                CSV.AppendDataToCsvDouble(filepathfile, recrddataMirrorAVG.ListX.ToArray());

                //计算插值
                double[] x = new double[] { 0, 0.8, 1, 2, 3, 4, 5, 7, 8, 9, 10, 12, 14, 16, 20 };
                //double[] y = DataTranslate.CalculateSegmentAverages(recrddataMirrorAVG.ListY.ToArray(), recrddataMirrorAVG.ListC.ToArray(), x);
                double[] y = InterpolateArray(recrddataMirrorAVG.ListY.ToArray(), recrddataMirrorAVG.ListC.ToArray(), x);
                y[y.Length - 1] = 1450;
                y[0] = 0;
                List<string> liststring = new List<string>();
                liststring.Add($"bar,此压力水平下的电流值mA/10");

                for (int i = 0; i < x.Length; i++)
                {
                    liststring.Add($"{x[i]} bar,{(y[i] / 10).ToString("F2")}");
                }

                //double currentX = LinearInterpolate(0.5, 1.35, 225, 280, 0.8);

                //str = "获取文件所在的目录：" + Path.GetDirectoryName(filePath);
                //str = "获取文件的名称含有后缀：" + Path.GetFileName(filePath);
                //str = "获取文件的名称没有后缀：" + Path.GetFileNameWithoutExtension(filePath);
                //str = "获取路径的后缀扩展名称：" + Path.GetExtension(filePath);
                //str = "获取路径的根目录：" + Path.GetPathRoot(filePath);
                var ret = CSV.SaveProductList2CSV(liststring, Path.GetDirectoryName(filepathfile), $"\\{projectItem.Name}_Test_Data_LinearInterpolation_SN{projectItem.SN}_{dtdatetime.ToString("HH_mm_ss")}.csv");
                return true;
            }
            catch (Exception ex)
            {
                Helpers.Log.ErrorByTime($"{projectItem.Name} Set CFCRCPTO Step Error:{ex.Message}");
                return false;
            }
        }
        public static async Task<bool> SetCFCRCPTOStepPulse(StepTest test, string cfcrcpto, ProjectItem projectItem)
        {
            try
            {
                var recrddata = new ShowDataRecord
                {
                    Title = cfcrcpto,
                    Unit = "mA",
                    ListC = new List<double>(),
                    ListS = new List<double>(),
                    ListX = new List<double>(),
                    ListY = new List<double>(),
                };
                var recrddataAVGStep = new ShowDataRecord
                {
                    Title = cfcrcpto,
                    Unit = "mA",
                    ListC = new List<double>(),
                    ListS = new List<double>(),
                    ListX = new List<double>(),
                    ListY = new List<double>(),
                };

                await Task.Run(async () =>
                {
                    int startRecodS = 2;//记录开始时间
                    for (int i = 0; i < test.Repeat; i++)
                    {
                        if (cfcrcpto == "CF")
                            SetCurrenCF(test.ValueStart);
                        else if (cfcrcpto == "CR")
                            SetCurrenCR(test.ValueStart);
                        else if (cfcrcpto == "CPTO")
                            SetCurrenCPTO(test.ValueStart);

                        int countstep = 0;
                        double addstep = 0;
                        double addstepCtl = 0;

                        Stopwatch stopwatch = new Stopwatch();
                        stopwatch.Start();
                        while (true)
                        {
                            if (!ShowStatus.IsRunning)
                                return;
                            await Task.Delay(MainWindow.configapp.TCUInterval);
                            if (stopwatch.ElapsedMilliseconds >= startRecodS * 1000)//达到记录开始时间
                            {
                                countstep++;
                                double pressure = 0;
                                double ctr_current = 0;
                                if (cfcrcpto == "CF")
                                {
                                    pressure = ShowStatus.CF_Pressure;
                                    ctr_current = ShowStatus.CF_ControlCurrent;
                                }
                                else if (cfcrcpto == "CR")
                                {
                                    pressure = ShowStatus.CR_Pressure;
                                    ctr_current = ShowStatus.CR_ControlCurrent;
                                }
                                else if (cfcrcpto == "CPTO")
                                {
                                    pressure = ShowStatus.CPTO_Pressure;
                                    ctr_current = ShowStatus.PTO_ControlCurrent;
                                }
                                double ms = stopwatch.Elapsed.TotalSeconds;
                                recrddata.ListC.Add(ctr_current);
                                recrddata.ListX.Add(ms);
                                recrddata.ListY.Add(pressure);
                                addstep += pressure;
                                addstepCtl += ctr_current;
                            }
                            if (stopwatch.ElapsedMilliseconds >= test.StepValue * 1000)//达到秒数
                            {
                                break;
                            }
                        }
                        recrddataAVGStep.ListC.Add(addstepCtl / countstep);
                        recrddataAVGStep.ListY.Add(addstep / countstep);

                        stopwatch.Restart();

                        if (cfcrcpto == "CF")
                            SetCurrenCF(test.ValueEnd);
                        else if (cfcrcpto == "CR")
                            SetCurrenCR(test.ValueEnd);
                        else if (cfcrcpto == "CPTO")
                            SetCurrenCPTO(test.ValueEnd);

                        while (true)
                        {
                            if (!ShowStatus.IsRunning)
                                return;
                            await Task.Delay(MainWindow.configapp.TCUInterval);

                            if (stopwatch.ElapsedMilliseconds >= startRecodS * 1000)//达到记录开始时间
                            {
                                countstep++;
                                double pressure = 0;
                                double ctr_current = 0;
                                if (cfcrcpto == "CF")
                                {
                                    pressure = ShowStatus.CF_Pressure;
                                    ctr_current = ShowStatus.CF_ControlCurrent;
                                }
                                else if (cfcrcpto == "CR")
                                {
                                    pressure = ShowStatus.CR_Pressure;
                                    ctr_current = ShowStatus.CR_ControlCurrent;
                                }
                                else if (cfcrcpto == "CPTO")
                                {
                                    pressure = ShowStatus.CPTO_Pressure;
                                    ctr_current = ShowStatus.PTO_ControlCurrent;
                                }
                                double ms = stopwatch.Elapsed.TotalSeconds;
                                recrddata.ListC.Add(ctr_current);
                                recrddata.ListX.Add(ms);
                                recrddata.ListY.Add(pressure);
                                addstep += pressure;
                                addstepCtl += ctr_current;
                            }
                            if (stopwatch.ElapsedMilliseconds >= test.StepKeep * 1000)//达到秒数
                            {
                                break;
                            }
                        }
                        recrddataAVGStep.ListC.Add(addstepCtl / countstep);
                        recrddataAVGStep.ListY.Add(addstep / countstep);

                        stopwatch.Stop();
                    }
                });

                var dtdatetime = DateTime.Now;

                //报存原始数据
                SaveData(projectItem, cfcrcpto, recrddata, dtdatetime);
                var recrddataAlpha = new ShowDataRecord
                {
                    Title = cfcrcpto,
                    Unit = "mA",
                    ListC = new List<double>(),
                    ListS = new List<double>(),
                    ListX = new List<double>(),
                    ListY = new List<double>(),
                };
                recrddataAlpha = GetLowPassFilter(MainWindow.configapp.FilterAlpha, recrddata);
                SaveDataFilter(projectItem, cfcrcpto, recrddataAlpha, dtdatetime);

                //保存平均值
                string filepathfile = await SaveData(projectItem, cfcrcpto + "_AVG", recrddataAVGStep, dtdatetime);
                return true;
            }
            catch (Exception ex)
            {
                Helpers.Log.ErrorByTime($"{projectItem.Name} Set CFCRCPTO Step Pulse Error:{ex.Message}");
                return false;
            }
        }
        public static async Task<bool> SetCFCRCPTOStepKP(StepTest test, string cfcrcpto, ProjectItem projectItem)
        {
            try
            {
                var recrddata = new ShowDataRecord
                {
                    Title = cfcrcpto,
                    Unit = "mA",
                    ListC = new List<double>(),
                    ListS = new List<double>(),
                    ListX = new List<double>(),
                    ListY = new List<double>(),
                };
                var recrddataAlpha = new ShowDataRecord
                {
                    Title = cfcrcpto,
                    Unit = "mA",
                    ListC = new List<double>(),
                    ListS = new List<double>(),
                    ListX = new List<double>(),
                    ListY = new List<double>(),
                };
                var recrddataMirrorAVG = new ShowDataRecord
                {
                    Title = cfcrcpto,
                    Unit = "mA",
                    ListC = new List<double>(),
                    ListS = new List<double>(),
                    ListX = new List<double>(),
                    ListY = new List<double>(),
                };
                var recrddataAVGStep = new ShowDataRecord
                {
                    Title = cfcrcpto,
                    Unit = "mA",
                    ListC = new List<double>(),
                    ListS = new List<double>(),
                    ListX = new List<double>(),
                    ListY = new List<double>(),
                };
                bool isGetKPMaxPressure = false;
                int kpMaxCount = 0;
                float kpMaxAVG = 0.0f;
                float kpMaxPressure = 0.0f;

                int stepPiek = 0;
                await Task.Run(async () =>
                {
                    int lastvaule = test.ValueStart;
                    //int step = ((1610 - 0)+40-1) / 40;//为了得到不舍只入。
                    int step = ((test.ValueEnd - test.ValueStart) + test.StepValue - 1) / test.StepValue;//为了得到不舍只入的步数。
                    int startRecodS = 2;//记录开始时间
                    stepPiek = step;//记录峰值阶跃数字

                    for (int i = 0; i < step + 1; i++)
                    {
                        lastvaule = test.ValueStart + i * test.StepValue;
                        if (cfcrcpto == "CF")
                            SetCurrenCF(lastvaule);
                        else if (cfcrcpto == "CR")
                            SetCurrenCR(lastvaule);
                        else if (cfcrcpto == "CPTO")
                            SetCurrenCPTO(lastvaule);

                        int countstep = 0;
                        double addstep = 0;
                        double addstepCtl = 0;
                        bool ismaxspeed = false;//是否达到最大速度

                        Stopwatch stopwatch = new Stopwatch();
                        stopwatch.Start();
                        Stopwatch stopwatchMax = new Stopwatch();
                        while (true)
                        {
                            if (!ShowStatus.IsRunning)
                                return;
                            await Task.Delay(MainWindow.configapp.TCUInterval);

                            var outspeedABS = Math.Abs(ShowStatus.DataTCU.TransmInSpeed);

                            if (stopwatch.ElapsedMilliseconds >= startRecodS * 1000)//达到记录开始时间
                            {
                                countstep++;
                                double pressure = 0;
                                double ctr_current = 0;

                                if (cfcrcpto == "CF")
                                {
                                    pressure = ShowStatus.CF_Pressure;
                                    ctr_current = ShowStatus.CF_ControlCurrent;
                                }
                                else if (cfcrcpto == "CR")
                                {
                                    pressure = ShowStatus.CR_Pressure;
                                    ctr_current = ShowStatus.CR_ControlCurrent;
                                }
                                else if (cfcrcpto == "CPTO")
                                {
                                    pressure = ShowStatus.CPTO_Pressure;
                                    ctr_current = ShowStatus.PTO_ControlCurrent;
                                }
                                double ms = stopwatch.Elapsed.TotalSeconds;
                                recrddata.ListC.Add(ctr_current);
                                recrddata.ListS.Add(lastvaule);
                                var mss = i * test.StepKeep + ms;
                                recrddata.ListX.Add(mss);
                                recrddata.ListY.Add(pressure);

                                addstep += pressure;
                                addstepCtl += ctr_current;
                            }

                            ///记录第一个到达的对应转速所对应的压力
                            if (!isGetKPMaxPressure && outspeedABS > projectItem.SetPointCurrentKP.KPMaxOutSpeed)
                            {
                                isGetKPMaxPressure = true;
                                if (cfcrcpto == "CF")
                                    kpMaxPressure = (float)ShowStatus.CF_Pressure;
                                else if (cfcrcpto == "CR")
                                    kpMaxPressure = (float)ShowStatus.CR_Pressure;
                                else if (cfcrcpto == "CPTO")
                                    kpMaxPressure = (float)ShowStatus.CPTO_Pressure;
                            }

                            if (i == 0)
                            {
                                if (stopwatch.ElapsedMilliseconds >= projectItem.SetPointCurrentKP.KPStartKeep * 1000)
                                {
                                    break;
                                }
                            }
                            else if (i == step) //若达到设定峰值，转速还不到设定范围，输出结果不合格
                            {
                                if (outspeedABS > (projectItem.SetPointCurrentKP.KPMaxOutSpeed - 30) && outspeedABS < (projectItem.SetPointCurrentKP.KPMaxOutSpeed + 30))
                                {
                                    if (!ismaxspeed)
                                    {
                                        ismaxspeed = true;
                                        stopwatchMax.Start();
                                    }

                                    if (ismaxspeed)
                                    {
                                        kpMaxCount++;
                                        if (cfcrcpto == "CF")
                                            kpMaxAVG += (float)ShowStatus.CF_Pressure;
                                        else if (cfcrcpto == "CR")
                                            kpMaxAVG += (float)ShowStatus.CR_Pressure;
                                        else if (cfcrcpto == "CPTO")
                                            kpMaxAVG += (float)ShowStatus.CPTO_Pressure;
                                    }
                                    //若转速波动在设定范围内，则完成测试，输出结果合格
                                    if (stopwatchMax.ElapsedMilliseconds >= projectItem.SetPointCurrentKP.KPEndKeep * 1000)
                                    {
                                        stopwatchMax.Stop();
                                        i = step + 1; //直接跳到结束
                                        projectItem.IsItemOKNG = true; //测试合格
                                        break;
                                    }
                                }
                                else if (stopwatch.ElapsedMilliseconds >= projectItem.SetPointCurrentKP.KPEndKeep * 1000)
                                {
                                    ////若达到设定峰值，转速还不到设定范围，输出结果不合格
                                    break;
                                }
                            }
                            else
                            {
                                //峰值为变量，通过判断输出轴速度1339.2（±30-50rpm）范围内，则电流不再增加，维持5S后测试结束。若转速稳定不住超出范围，则再增加梯度，直至数值稳定

                                //升阶问题
                                //1.峰值时间与稳定输出轴转速一致没有问题
                                //2.升阶过程中，若输出轴转速瞬间达到设定转速，这时暂停升阶，判断转速稳定性。若峰值时间内不稳定以及低于设定转速，则继续升阶；若转速波动在设定范围内，则完成测试，输出结果合格；若转速波动高于设定范围则停止测试，输出结果不合格；若达到设定峰值，转速还不到设定范围，输出结果不合格

                                if (outspeedABS > (projectItem.SetPointCurrentKP.KPMaxOutSpeed - 30) && outspeedABS < (projectItem.SetPointCurrentKP.KPMaxOutSpeed + 30))
                                {
                                    if (!ismaxspeed)
                                    {
                                        ismaxspeed = true;
                                        stopwatchMax.Start();
                                    }

                                    if (ismaxspeed)
                                    {
                                        kpMaxCount++;
                                        if (cfcrcpto == "CF")
                                            kpMaxAVG += (float)ShowStatus.CF_Pressure;
                                        else if (cfcrcpto == "CR")
                                            kpMaxAVG += (float)ShowStatus.CR_Pressure;
                                        else if (cfcrcpto == "CPTO")
                                            kpMaxAVG += (float)ShowStatus.CPTO_Pressure;
                                    }

                                    //若转速波动在设定范围内，则完成测试，输出结果合格
                                    if (stopwatchMax.ElapsedMilliseconds >= projectItem.SetPointCurrentKP.KPEndKeep * 1000)
                                    {
                                        stopwatchMax.Stop();
                                        i = step + 1; //直接跳到结束
                                        projectItem.IsItemOKNG = true; //测试合格
                                        break;
                                    }

                                    //若转速波动高于设定范围则停止测试，输出结果不合格；

                                    //若输出轴转速瞬间达到设定转速，这时暂停升阶，判断转速稳定性。
                                    //continue;
                                }
                                else if (outspeedABS > (projectItem.SetPointCurrentKP.KPMaxOutSpeed + 30))
                                {
                                    //若转速波动高于设定范围则停止测试，输出结果不合格；
                                    i = step + 1; //直接跳到结束
                                    break;

                                }
                                else//若峰值时间内不稳定以及低于设定转速，则继续升阶；
                                {
                                    ismaxspeed = false;
                                    stopwatchMax.Stop();
                                    //记录的平均值清空
                                    kpMaxCount = 0;
                                    kpMaxAVG = 0.0f;
                                    
                                    if (stopwatch.ElapsedMilliseconds >= test.StepKeep * 1000)//达到阶跃秒数
                                    {
                                        break;
                                    }
                                }
                            }
                        }
                        recrddataAVGStep.ListC.Add(addstepCtl / countstep);
                        recrddataAVGStep.ListY.Add(addstep / countstep);
                        stopwatch.Stop();
                    }
                });

                projectItem.SetPointCurrentKP.KPMaxPressure = kpMaxPressure;
                projectItem.SetPointCurrentKP.KPMaxAVGPressure = kpMaxCount > 0 ? kpMaxAVG / kpMaxCount : 0.0f;

                var dtdatetime = DateTime.Now;
                //报存原始数据
                SaveData(projectItem, cfcrcpto, recrddata, dtdatetime);
                //转换低通滤波数据
                recrddataAlpha = GetLowPassFilter(MainWindow.configapp.FilterAlpha, recrddata);
                SaveDataFilter(projectItem, cfcrcpto, recrddataAlpha, dtdatetime);

                //保存平均值
                string filepathfile = await SaveData(projectItem, cfcrcpto + "_AVG", recrddataAVGStep, dtdatetime);
                //计算对称位置的平均值
                recrddataMirrorAVG.ListC = DataTranslate.CalculateSymmetricAverages(recrddataAVGStep.ListC);//C是平均电流
                recrddataMirrorAVG.ListX.Clear();
                for (int i = 0; i < recrddataMirrorAVG.ListY.Count; i++)
                {
                    recrddataMirrorAVG.ListX.Add(recrddataMirrorAVG.ListY[i]);//X是对称平均压力
                }
                //保存对称位置平均值
                //SaveData(projectItem, cfcrcpto + "_Mirror_AVG", recrddataMirrorAVG);
                CSV.AppendDataToCsvDouble(filepathfile, recrddataMirrorAVG.ListX.ToArray());
                return true;
            }
            catch (Exception ex)
            {
                Helpers.Log.ErrorByTime($"{projectItem.Name} Set CFCRCPTO Step KP Error:{ex.Message}");
                return false;
            }
        }

        public static async Task<string> SaveData(ProjectItem projectItem, string name, ShowDataRecord data, DateTime dtdatetime)
        {
            //保存数据
            try
            {
                string filepath = $"D:\\Record\\{dtdatetime.ToString("yyyy")}\\{dtdatetime.ToString("MM")}\\{dtdatetime.ToString("dd")}\\StepTest\\";
                string filepathname = filepath + $"{name}_Test_Data_Horizontal_SN_{projectItem.SN}_{dtdatetime.ToString("HH_mm_ss")}.csv";
                double[] ms = data.ListX.ToArray();
                double[] dataY = data.ListY.ToArray();
                double[] dataS = data.ListS.ToArray();
                double[] dataC = data.ListC.ToArray();
                var list = new List<double[]> { dataC, dataY };
                var ret = CSV.WriteDoubleArrayToCsv(list, filepathname);
                return filepathname;
            }
            catch (Exception ex)
            {
            }
            return "";
        }
        /// <summary>
        /// 保存低通滤波数据csv
        /// </summary>
        /// <param name="projectItem"></param>
        /// <param name="name"></param>
        /// <param name="data"></param>
        /// <param name="dtdatetime"></param>
        /// <returns></returns>
        public static async Task<string> SaveDataFilter(ProjectItem projectItem, string name, ShowDataRecord data, DateTime dtdatetime)
        {
            //保存数据
            try
            {
                string filepath = $"D:\\Record滤波数据\\{dtdatetime.ToString("yyyy")}\\{dtdatetime.ToString("MM")}\\{dtdatetime.ToString("dd")}\\StepTest\\";
                string filepathname = filepath + $"{name}_Test_LowPassFilterData_Horizontal_SN_{projectItem.SN}_{dtdatetime.ToString("HH_mm_ss")}.csv";
                double[] ms = data.ListX.ToArray();
                double[] dataY = data.ListY.ToArray();
                double[] dataS = data.ListS.ToArray();
                double[] dataC = data.ListC.ToArray();
                var list = new List<double[]> { dataC, dataY };
                var ret = CSV.WriteDoubleArrayToCsv(list, filepathname);
                return filepathname;
            }
            catch (Exception ex)
            {
            }
            return "";
        }
        static double LinearInterpolate(double x1, double x2, double y1, double y2, double x)
        {
            return y1 + (y2 - y1) * (x - x1) / (x2 - x1);
        }
        static double[] InterpolateArray(double[] a, double[] b, double[] x)
        {
            if (a.Length != b.Length)
                throw new ArgumentException("a 和 b 长度必须相同。");

            double[] y = new double[x.Length];

            for (int i = 0; i < x.Length; i++)
            {
                double xi = x[i];

                // 如果在边界之外，可以选择Clamp或外推
                if (xi <= a[0])
                {
                    y[i] = b[0];
                    continue;
                }
                if (xi >= a[a.Length - 1])
                {
                    y[i] = b[b.Length - 1];
                    continue;
                }

                // 找到区间 [a[j], a[j+1]]
                int j = 0;
                while (j < a.Length - 1 && xi > a[j + 1])
                    j++;

                // 线性插值
                double t = (xi - a[j]) / (a[j + 1] - a[j]);
                y[i] = b[j] + t * (b[j + 1] - b[j]);
            }

            return y;
        }
        /// <summary>
        /// 设置CPTO使能
        /// </summary>
        /// <param name="isEN"></param>
        /// <returns></returns>
        public static void SetCPTOEn(bool isEN)
        {
            Task.Run(() =>
            {
                IsTCUOnline = TCUConfig.SetCPTOEnable(isEN);
            });
        }
        /// <summary>
        /// 设置CPTO开关
        /// </summary>
        /// <param name="onoff"></param>
        /// <returns></returns>
        public static void SetCPTOOnOff(bool onoff)
        {
            Task.Run(() =>
            {
                IsTCUOnline = TCUConfig.SetCPTOOnOff(onoff);
            });

        }
        /// <summary>
        /// CF/CR使能控制
        /// </summary>
        /// <param name="isEN"></param>
        public static void SetCFCREn(bool isEN)
        {
            Task.Run(() =>
            {
                IsTCUOnline = TCUConfig.SetCFCREnable(isEN);
            });

        }
        /// <summary>
        /// 0x2:R  0x3:N   0x4:F  Other:N
        /// </summary>
        /// <param name="shp"></param>
        /// <returns></returns>
        public static void SetCFCRShp(ClutcCFCR cfr)
        {
            Task.Run(() =>
            {
                IsTCUOnline = TCUConfig.SetCFCRShp(cfr);
            });
        }
        /// <summary>
        /// 0x0:变速器种类1    0x1:变速器种类2    0x2:变速器种类3  
        /// </summary>
        /// <param name="shp"></param>
        /// <returns></returns>
        public static bool SetTransmitType(byte shp)
        {
            return TCUConfig.SetTransmitType(shp);
        }
        /// <summary>
        /// 设置各个通道电流的使能
        /// 0bit: CF  CurrentChannel      1bit: CR CurrentChannel    2bit: PTO CurrentChannel   Other bit :Reserve
        /// </summary>
        /// <param name="typ"></param>
        /// <returns></returns>
        public static void SetCurrentChan(CurrentChannel chn)
        {
            Task.Run(() =>
            {
                IsTCUOnline = TCUConfig.SetCurrentChan(chn);
            });
        }
        /// <summary>
        /// 设置通道电流
        /// </summary>
        /// <param name="chn"></param>
        /// <returns></returns>
        public static void SetCurrenCPTO(int ma)
        {
            Task.Run(() =>
            {
                IsTCUOnline = TCUConfig.SetCurrentCPTO(ma);
            });
        }
        /// <summary>
        /// 设置CF通道电流
        /// </summary>
        /// <param name="ma"></param>
        public static void SetCurrenCF(int ma)
        {

            Task.Run(() =>
            {
                IsTCUOnline = TCUConfig.SetCurrentCF(ma);
            });
        }
        /// <summary>
        /// 设置CR通道电流
        /// </summary>
        /// <param name="ma"></param>
        public static void SetCurrenCR(int ma)
        {
            Task.Run(() =>
            {
                IsTCUOnline = TCUConfig.SetCurrentCR(ma);
            });
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="ma"></param>
        public static async Task SendNVHSNTest(string sn, string test)
        {
            Helpers.Log.SaveNVHSend($"SN:{sn};TEST:{test}");
            //await Task.Delay(500);
            await NVHConfig.SetSNTest(sn, test);
        }

        /// <summary>
        /// 设置驱动端状态，准备提速前的步骤完成
        /// </summary>
        /// <param name="isEn">true，启动。false停止</param>
        /// <returns></returns>
        public static async Task<bool> StartOrStopEngineReady(bool isEn)
        {
            if (isEn)
                return await PLCControl.StartEngineReady();
            else
                return await PLCControl.StopEngine();
        }

        private static ShowDataRecord GetLowPassFilter(double alpha, ShowDataRecord sdr)
        {

            var filter = new LowPassFilter(alpha);
            try
            {
                var listY = new List<double>();
                var listC = sdr.ListC;
                var listX = sdr.ListX;
                var ListS = sdr.ListS;
                if (sdr.ListY != null)
                {
                    foreach (var dy in sdr.ListY)
                    {
                        listY.Add(filter.Filter(dy));
                    }
                }
                return new ShowDataRecord
                {
                    From = sdr.From,
                    AppName = sdr.AppName,
                    Title = sdr.Title,
                    Unit = sdr.Unit,
                    ListX = listX,
                    ListY = listY,
                    ListC = listC,
                    ListS = listC
                };
            }
            catch (Exception)
            {

                throw;
            }
            return null;
        }
        public static string GetLowPassFilterStr(string str, LowPassFilter filter)
        {
            try
            {
                var ret = double.TryParse(str, out double strfilter);
                if (ret)
                    return filter.Filter(strfilter).ToString();
            }
            catch (Exception)
            {

            }
            return "";
        }
    }
}
